package cn.com.cifi.mars.bean.bo.returnPlan;

import cn.com.cifi.mars.bean.dto.returnPlan.ReturnSignMyReceiptsDto;
import cn.com.cifi.mars.bean.dto.returnPlan.ReturnSignReceivableDto;
import cn.com.cifi.mars.bean.dto.returnPlan.ReturnSignRecordsDto;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.collections4.MapUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 回款明源签约数据
 * @author: JingYuanXiang
 * @date: 2020/11/12 15:08
 */
@Data
public class ReturnPlanMySaleDataBO extends ReturnPlanSaleDataBO{
    @ApiModelProperty(name = "returnSignReceivableList", value = "签约应收列表")
    List<ReturnSignReceivableDto> returnSignReceivableList;
    @ApiModelProperty(name = "returnSignReceiptsList", value = "签约实收列表")
    List<ReturnSignMyReceiptsDto> returnSignReceiptsList;

    @ApiModelProperty(name = "contractGUIDList", value = "合同id列表")
    List<String> contractGUIDList = new ArrayList<>();

    @ApiModelProperty(name = "recordsMonthMap", value = "签约金额Map(key:合同id,value:金额)")
    private Map<String, BigDecimal> recordsMonthMap = new HashMap();

    @ApiModelProperty(name = "receivableMoneyByGroupIdMap", value = "签约应收Map(key:组团id,value:(key:组合业态编码,value:(key:合同id,value:(key:年月,value:金额))")
    private Map<String,Map<String,Map<String, Map<String, BigDecimal>>>> receivableMoneyByGroupIdMap = new HashMap();


    //初始化Map
    @Override
    public void initializeMap(){
        if(CollectionUtils.isNotEmpty(returnSignRecordsList)){
            contractGUIDList = returnSignRecordsList.stream().map(ReturnSignRecordsDto::getContractGUID).collect(Collectors.toList());

            this.recordsMonthMap = returnSignRecordsList.stream()
                    .collect(Collectors.toMap(ReturnSignRecordsDto::getContractGUID, ReturnSignRecordsDto::getMoney));

            this.recordsRoomIdListByGroupIdMap = returnSignRecordsList.stream().
            collect(Collectors.groupingBy(ReturnSignRecordsDto::getGroupId,
                    Collectors.groupingBy(ReturnSignRecordsDto::getCombinationProductCode,
                    Collectors.mapping(ReturnSignRecordsDto::getContractGUID, Collectors.toList()))));
        }
        if(CollectionUtils.isNotEmpty(returnSignReceivableList)) {
            this.receivableMoneyByGroupIdMap = returnSignReceivableList.stream()
                    .filter(s->contractGUIDList.contains(s.getContractGUID())).
                    collect(Collectors.groupingBy(ReturnSignReceivableDto::getGroupId,
                            Collectors.groupingBy(ReturnSignReceivableDto::getCombinationProductCode,
                            Collectors.groupingBy(ReturnSignReceivableDto::getContractGUID,
                                    Collectors.toMap(ReturnSignReceivableDto::getYearMonth, ReturnSignReceivableDto::getMoney, BigDecimal::add)))));

            this.lastReceivableTimeByGroupIdMap = returnSignReceivableList.stream()
                    .filter(s -> contractGUIDList.contains(s.getContractGUID()))
                    .collect(Collectors.groupingBy(ReturnSignReceivableDto::getGroupId,
                            Collectors.toMap(ReturnSignReceivableDto::getCombinationProductCode, ReturnSignReceivableDto::getYearMonth,
                                    (s1, s2) -> LocalDateTimeUtils.compareYearMonth(s1, s2) >= 0 ? s1 : s2)));
        }
        if(CollectionUtils.isNotEmpty(returnSignReceiptsList)){
            this.receiptsMoneyByGroupIdMapA = returnSignReceiptsList.stream().
                    filter(s->contractGUIDList.contains(s.getContractGUID())).
                    collect(Collectors.groupingBy(ReturnSignMyReceiptsDto::getGroupId,
                            Collectors.groupingBy(ReturnSignMyReceiptsDto::getCombinationProductCode,
                                    Collectors.groupingBy(ReturnSignMyReceiptsDto::getYearMonth,
                                            Collectors.toMap(ReturnSignMyReceiptsDto::getContractGUID, ReturnSignMyReceiptsDto::getMoney, BigDecimal::add)))));
            this.receiptsMoneyByGroupIdMapB = returnSignReceiptsList.stream().
                    filter(s->contractGUIDList.contains(s.getContractGUID())).
                    collect(Collectors.groupingBy(ReturnSignMyReceiptsDto::getGroupId,
                            Collectors.groupingBy(ReturnSignMyReceiptsDto::getCombinationProductCode,
                                    Collectors.groupingBy(ReturnSignMyReceiptsDto::getContractGUID,
                                            Collectors.toMap(ReturnSignMyReceiptsDto::getYearMonth, ReturnSignMyReceiptsDto::getMoney, BigDecimal::add)))));

            this.zlReceiptsMoneyByGroupIdMap = returnSignReceiptsList.stream().
                    filter(s->contractGUIDList.contains(s.getContractGUID()) && s.getDataType().equals("增量")).
                    collect(Collectors.groupingBy(ReturnSignMyReceiptsDto::getGroupId,
                            Collectors.groupingBy(ReturnSignMyReceiptsDto::getCombinationProductCode,
                                    Collectors.toMap(ReturnSignMyReceiptsDto::getYearMonth, ReturnSignMyReceiptsDto::getMoney, BigDecimal::add))));

            this.clReceiptsMoneyByGroupIdMap = returnSignReceiptsList.stream().
                    filter(s->contractGUIDList.contains(s.getContractGUID()) && s.getDataType().equals("存量")).
                    collect(Collectors.groupingBy(ReturnSignMyReceiptsDto::getGroupId,
                            Collectors.groupingBy(ReturnSignMyReceiptsDto::getCombinationProductCode,
                                    Collectors.toMap(ReturnSignMyReceiptsDto::getYearMonth, ReturnSignMyReceiptsDto::getMoney, BigDecimal::add))));
        }

        if(MapUtils.isEmpty(recordsMonthMap)){
            this.recordsMonthMap = new HashMap<>();
        }
        if(MapUtils.isEmpty(recordsRoomIdListByGroupIdMap)){
            this.recordsRoomIdListByGroupIdMap = new HashMap<>();
        }
        if(MapUtils.isEmpty(receiptsMoneyByGroupIdMapA)){
            this.receiptsMoneyByGroupIdMapA = new HashMap<>();
        }
        if(MapUtils.isEmpty(receiptsMoneyByGroupIdMapB)){
            this.receiptsMoneyByGroupIdMapB = new HashMap<>();
        }
        if(MapUtils.isEmpty(zlReceiptsMoneyByGroupIdMap)){
            this.zlReceiptsMoneyByGroupIdMap = new HashMap<>();
        }
        if(MapUtils.isEmpty(clReceiptsMoneyByGroupIdMap)){
            this.clReceiptsMoneyByGroupIdMap = new HashMap<>();
        }
    }

    /**
     * 获取签约应收-在等于指定月应收的金额
     * @param groupId 组团id
     * @param combinationProductCode 组合业态编码
     * @param yearMonth 年月
     * @return
     */
    public BigDecimal getReceivableMoneyByEQYearMonth(String groupId,String combinationProductCode, String yearMonth) {
        //总金额
        BigDecimal money = BigDecimal.ZERO;

        Map<String, Map<String, Map<String, BigDecimal>>> receivableMoneyByCombinationProductCodeMap = receivableMoneyByGroupIdMap.get(groupId);
        if(MapUtils.isEmpty(receivableMoneyByCombinationProductCodeMap)){
            return money;
        }
        Map<String, Map<String, BigDecimal>> receivableMap = receivableMoneyByCombinationProductCodeMap.get(combinationProductCode);
        if(MapUtils.isEmpty(receivableMap)){
            return money;
        }
        //获取等于指定月应收的金额
        for (Map.Entry<String, Map<String, BigDecimal>> map : receivableMap.entrySet()){
            BigDecimal reduce = map.getValue().entrySet().stream()
                    .filter(e -> compareYearMonth(e.getKey(), yearMonth) == 0)
                    .map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);

            money = money.add(reduce);
        }
        return money;

    }

    /**
     /**
     * 获取签约增量实收-指定房间id列表在指定月增量实收的金额
     * @param combinationProductCode 组合业态编码
     * @param yearMonth 年月
     * @return
     */
    @Override
    public BigDecimal getZlReceiptsMoneyByYearMonth(String groupId,String combinationProductCode, String yearMonth) {
        //总金额
        BigDecimal money = BigDecimal.ZERO;
        if(CollectionUtils.isEmpty(contractGUIDList)){
            return money;
        }

        Map<String, BigDecimal> receiptsMoneyMap = new HashMap<>();
        if(MapUtils.isNotEmpty(zlReceiptsMoneyByGroupIdMap.get(groupId))
                && MapUtils.isNotEmpty(zlReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode))
                && null != zlReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode).get(yearMonth)) {
            return zlReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode).get(yearMonth);
        }else {
            return money;
        }
    }

    /**
     * 获取签约存量实收-指定房间id列表在指定月存量实收的金额
     * @param combinationProductCode 组合业态编码
     * @param yearMonth 年月
     * @return
     */
    @Override
    public BigDecimal getClReceiptsMoneyByYearMonth(String groupId,String combinationProductCode, String yearMonth) {
        //总金额
        BigDecimal money = BigDecimal.ZERO;
        if(CollectionUtils.isEmpty(contractGUIDList)){
            return money;
        }
        if(MapUtils.isNotEmpty(clReceiptsMoneyByGroupIdMap.get(groupId))
                && MapUtils.isNotEmpty(clReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode))
                && null != clReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode).get(yearMonth)) {
            return clReceiptsMoneyByGroupIdMap.get(groupId).get(combinationProductCode).get(yearMonth);
        }else {
            return money;
        }
    }

    /**
     * 获取签约实收-在等于指定月实收的金额
     * @param combinationProductCode 组合业态编码
     * @param yearMonth 年月
     * @return
     */
    @Override
    public BigDecimal getReceiptsMoneyByYearMonth(String groupId,String combinationProductCode, String yearMonth) {
        //总金额
        BigDecimal money = BigDecimal.ZERO;

        Map<String, BigDecimal> receiptsMoneyMap = new HashMap<>();
        if(MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapA.get(groupId))
                && MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapA.get(groupId).get(combinationProductCode))
                && MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapA.get(groupId).get(combinationProductCode).get(yearMonth))) {
            receiptsMoneyMap = receiptsMoneyByGroupIdMapA.get(groupId).get(combinationProductCode).get(yearMonth);
        }else {
            return money;
        }

        money = receiptsMoneyMap.entrySet().stream().map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
        return money;
    }


    /**
     * 筛选指定合同id列表中当月及以前的实收大于当月及以前的应收的合同id列表
     * 获取其中当月及以前的实收大于当月及以前的应收的金额合计
     * @param groupId 组团id
     * @param combinationProductCode 组合业态编码
     * @param yearMonth 年月
     * @return
     */
    public BigDecimal getRefundable(String groupId,String combinationProductCode, String yearMonth) {
        //总金额
        BigDecimal money = BigDecimal.ZERO;
        if(null == recordsRoomIdListByGroupIdMap.get(groupId)){
            System.out.println(1);
        }

        //获取合同列表
        List<String> contractGUIDList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(recordsRoomIdListByGroupIdMap.get(groupId))
                && CollectionUtils.isNotEmpty(recordsRoomIdListByGroupIdMap.get(groupId).get(combinationProductCode))){
            contractGUIDList = recordsRoomIdListByGroupIdMap.get(groupId).get(combinationProductCode);
        }else {
            return money;
        }


        Map<String,Map<String, BigDecimal>> receiptsMap = new HashMap<>();
        if(MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapB.get(groupId))
                && MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapB.get(groupId).get(combinationProductCode))
                && MapUtils.isNotEmpty(receiptsMoneyByGroupIdMapB.get(groupId).get(combinationProductCode))) {
            receiptsMap = receiptsMoneyByGroupIdMapB.get(groupId).get(combinationProductCode);
        }else {
            return money;
        }

        for (String contractGUID : contractGUIDList){
            //签约金额
            BigDecimal receivableMoney =recordsMonthMap.get(contractGUID);
            //实收金额
            BigDecimal receiptsMoney = BigDecimal.ZERO;

            Map<String, BigDecimal> receiptsMoneyMap = receiptsMap.get(contractGUID);

            if(MapUtils.isNotEmpty(receiptsMoneyMap)) {
                receiptsMoney = receiptsMoneyMap.entrySet().stream()
                        .filter(e -> compareYearMonth(e.getKey(), yearMonth) < 0)
                        .map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            }

            if(receiptsMoney.compareTo(receivableMoney == null ? BigDecimal.ZERO : receivableMoney) > 0){
                money = money.add(receiptsMoney.subtract(receivableMoney));
            }
        }

        return money;
    }

}
